package org.subatu.orm.query.condition;


import org.springframework.util.Assert;
import org.subatu.orm.query.base.BaseSql;
import org.subatu.orm.query.base.CondEnum;
import org.subatu.orm.query.brige.JoinConditionAndBy;
import org.subatu.orm.query.function.FunctionToQueryColumnUtil;
import org.subatu.orm.query.function.SFunction;
import org.subatu.orm.query.table.CondColumn;
import org.subatu.orm.query.table.QueryColumn;
import org.subatu.orm.query.table.TableDef;

import java.util.List;

/**
 * 比较条件
 */
public interface JoinCondition extends BaseSql {

    // ********* 以下是构造 关系条件 *********
    default JoinConditionAndBy and_() {
        return makeCondition_(CondEnum.and);
    }

    default JoinConditionAndBy or_() {
        return makeCondition_(CondEnum.or);
    }

    default JoinConditionAndBy boxL_() {
        return makeCondition_(CondEnum.boxL);
    }

    default JoinConditionAndBy boxR_() {
        return makeCondition_(CondEnum.boxR);
    }

    // ********* 以下是构造 对比 条件 *********

    default <E> JoinConditionAndBy eq_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.eq, value);
    }

    default <E, B> JoinConditionAndBy eq_(SFunction<E> column, SFunction<B> columnJoin) {
        return makeCondition_(column, CondEnum.eq, columnJoin);
    }

    default <E> JoinConditionAndBy gt_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.gt, value);
    }

    default <E> JoinConditionAndBy ge_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.ge, value);
    }

    default <E> JoinConditionAndBy lt_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.lt, value);
    }

    default <E> JoinConditionAndBy le_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.le, value);
    }

    default <E> JoinConditionAndBy in_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.in, value);
    }

    default <E> JoinConditionAndBy notIn_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.notIn, value);
    }

    default <E> JoinConditionAndBy isNull_(SFunction<E> column) {
        return makeCondition_(column, CondEnum.isNull, null);
    }

    default <E> JoinConditionAndBy notNull_(SFunction<E> column) {
        return makeCondition_(column, CondEnum.notNull, null);
    }

    default <E> JoinConditionAndBy likeL_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.likeL, value);
    }

    default <E> JoinConditionAndBy likeR_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.likeR, value);

    }

    default <E> JoinConditionAndBy like_(SFunction<E> column, Object value) {
        return makeCondition_(column, CondEnum.like, value);

    }

    // ********* 以下是实际执行 *********

    // 创建 关系队列
    default JoinConditionAndBy makeCondition_(CondEnum relationEnum) {
        // 构造 关系
        CondColumn condColumn = new CondColumn(relationEnum);
        // 加入到条件队列
        this.getCondList_().add(condColumn);
        return (JoinConditionAndBy) this;
    }

    // 创建 查询队列
    default <E> JoinConditionAndBy makeCondition_(SFunction<E> function, CondEnum condEnum, Object value) {
        QueryColumn queryColumn = FunctionToQueryColumnUtil.getQueryColumn(function);
        if (value instanceof SFunction<?> functionJoin) {
            value = FunctionToQueryColumnUtil.getQueryColumn(functionJoin);
        }
        // 构造 查询条件
        CondColumn condColumn = new CondColumn(true, queryColumn, condEnum, value);
        // 加入到条件队列
        this.getCondList_().add(condColumn);
        return (JoinConditionAndBy) this;
    }

    // 获取 查询条件
    default List<CondColumn> getCondList_() {
        // 1. where ; 2 having
        if (sqlData().isWhere.flag == 1) {
            return sqlData().whereList;
        } else if (sqlData().isWhere.flag == 2) {
            return sqlData().havingList;
        }
        // 3. 剩下的, 生成的 条件全部加到 joinList
        Assert.notEmpty(sqlData().joinList, "on 条件前,先写 join 相关函数");
        TableDef joinTable = sqlData().joinList.get(sqlData().joinList.size() - 1);
        return joinTable.getJoinConditionList();
    }

}
